home *** CD-ROM | disk | FTP | other *** search
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; Title: vga.asm
- ; Date: 6/18/92
- ; Author: Randy Buckland (randy@ncsu.edu)
- ;
- ; Description:
- ; This is a VERY basic set of routines to provide high speed SVGA
- ; graphics for IBM-PC compatibiles that have a VGA interface that supports
- ; a VESA driver. These routines assume a 256-color mode and will not work
- ; for any type of mode. The following routines are provided:
- ;
- ; vgainit(int vesa_mode)
- ; vgapoint(int row, int column, int pixel_value)
- ; vgahline(int row, int start_column, int end_column, int pixel_value)
- ; vgaline(int x1, int y1, int x2, int y2, int pixel_value)
- ; vgasetcolor(char *colors, int start, int count)
- ; vgafill(int row, int column, int width, int height, int pixel_value)
- ; vgarect(char *source, int source_width, int row, int column,
- ; int width, int height)
- ;
- ; Copyright (c) 1992 by Randy Buckland
- ; Permission is given to use this code in any manner desired with the
- ; following provisions:
- ; 1. The user of the code is totally responsible for any damages
- ; that may be caused by it's use.
- ; 2. The author has no control or responsibility for any damages
- ; that may be caused by it's use.
- ; 3. This copyright notice must remain a part of this source file.
- ;
- .model large,c
- include macros.asm
-
- ;
- ; Global data for the VGA support routines
- ;
- vgadata segment word public 'VGADATA'
-
- Block dw 1 ; Current video memory block accessable
- BlockSz dw 0 ; Size of a video block in K
- BlockShift dw 0 ; Amount to shift bits by
- BlockEnd dw 0 ; Last valid address in block
- BlockMask dw 0 ; Mask used for block/offset operations
-
- WinAddr dw 0 ; Segment addr of window A block
- ;WinFunc dd 0 ; Far pointer to windowing function
- ScanWidth dw 0 ; Width of a scan line
-
- vgadata ends
-
- vgacode segment word public 'VGACODE'
- assume cs:vgacode,ds:vgadata
-
- ;
- ; Set current video memory block. This procedure assumes that ds already
- ; points to the vgadata segment. This routine will not modify any registers.
- ;
- ; Parameters:
- ; - block number to change to
- ;
- vgablock proc near
- push bp
- mov bp,sp
- push dx
-
- mov dx,[bp+4] ; Start of video memory
- cmp dx,Block
- je l1
- mov Block,dx
-
- push ax
- push bx
-
- mov ax,4f05h ; VESA set memory block
- mov bx,0000h ; Set window A
- int 10h
-
- pop bx
- pop ax
- l1:
- pop dx
- mov sp,bp
- pop bp
- ret
- vgablock endp
-
-
-
- ;
- ; Calculate block and offset values for a given row/column. Assumes that ds
- ; points to vgadata. Does NOT preserve registers. Returns block value in
- ; dx and offset in ax.
- ;
- ; Parameters:
- ; - row value
- ; - column value
- ;
- vgaoffset proc near
- push bp
- mov bp,sp
-
- mov ax,[bp+4] ; Get row
- mul ScanWidth ; Get starting block and offset in dx:ax
-
- add ax,[bp+6] ; Add start column offset
- jnc l1
- inc dx ; Just crossed block boundery
- l1:
- mov cx,BlockShift ; Get block size mask
- cmp cx,0 ; Is block size 64K?
- je l2 ; Yes, skip this section
-
- mov bx,ax ; Save old ax
- rol ax,cl
- and ax,BlockMask ; Save high bits
- rol dx,cl
- add dx,ax ; Add high bits to block value.
-
- mov ax,bx
- rol ax,cl
- or ax,BlockMask ; Set undesirable bits
- xor ax,BlockMask ; Clear bad bits
- ror ax,cl
- ;
- ; Set active block to calculated block if needed
- ;
- l2:
- cmp dx,Block
- je l3
- push dx
- call vgablock
- pop dx
- l3:
-
- mov sp,bp
- pop bp
- ret
- vgaoffset endp
-
-
-
- ;
- ; Initialize the display
- ; Parameters:
- ; Mode value to use
- ;
- public vgainit
- vgainit proc far
- ;
- ; Set up call frame
- ;
- Prefix
- sub sp,256 ; Make local variable space
- ;
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
-
- ;
- ; Get VGA information and set desired mode
- ;
- mov ax,4f02h ; VESA set mode function
- mov bx,[bp+6] ; 640x480 mode
- int 10h
-
- push ss
- pop es ; Load es with value of ss
- mov di,sp ; Point index at 256 byte temp space
- mov cx,[bp+6]
- mov ax,4f01h ; VESA get Super VGA mode information
- int 10h
-
- mov ax,es:[di+6]
- mov BlockSz,ax
-
- mov ax,es:[di+8]
- mov WinAddr,ax
-
- ; mov ax,es:[di+12]
- ; mov word ptr WinFunc,ax
-
- ; mov ax,es:[di+14]
- ; mov word ptr WinFunc+2,ax
-
- mov ax,es:[di+16]
- mov ScanWidth,ax
-
- ;
- ; Calculate block shift and end values
- ;
- mov ax,BlockSz
- mov bx,10
- mov cx,03ffh
- l1:
- sar ax,1
- inc bx
- sal cx,1
- inc cx
- cmp ax,1
- ja l1
-
- mov ax,16
- sub ax,bx
- mov BlockShift, ax
- mov BlockEnd, cx
- not cx
- xchg ax,cx
- rol ax,cl
- mov BlockMask,ax
-
- ;
- ; Set to start block
- ;
- xor ax,ax
- push ax
- call vgablock
- pop ax
-
- ;
- ; Remove call frame and exit
- ;
- add sp,256
- Postfix
- vgainit endp
-
-
- ;
- ; Draw a single point
- ;
- ; Parameters:
- ; - Row of point
- ; - Column of point
- ; - Pixel value to use
- ;
- vgapoint proc far
- Prefix
-
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
- ;
- ; Load window pointers
- ;
- mov ax,WinAddr
- mov es,ax ; Set ES to point to video memory
-
- push [bp+8] ; Column
- push [bp+6] ; Row
- call vgaoffset
- add sp,4
-
- ;
- ; Draw point
- ;
- mov di,ax ; Put offset in index regester
- mov ax,[bp+10] ; bl has pixel value
- cld
- stosb
-
- Postfix
- vgapoint endp
-
-
-
- ;
- ; Draw a horizontal line. Line is assumed to start on even boundry and
- ; have length be an even value for speed.
- ;
- ; Parameters:
- ; - Row for line
- ; - Start column
- ; - End column
- ; - Pixel value
- ;
- vgahline proc far
- Prefix
- ;
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
- ;
- ; Load window pointers
- ;
- mov ax,WinAddr
- mov es,ax ; Set ES to point to video memory
-
- push [bp+8]
- push [bp+6]
- call vgaoffset
- add sp,4
-
- ;
- ; Setup control parameters for line draw.
- ;
- mov di, ax ; Offset in di
- mov ax,[bp+12]
- mov ah,al ; ax has duplicated pixel value in bl and bh
-
- mov cx,BlockEnd ; Last point in counter
- sub cx,di ; cx has number of legal bytes-1
-
- mov bx,[bp+10]
- sub bx,[bp+8] ; bx has number to write - 1
-
- cmp bx,cx
- ja l1
- mov cx,bx ; Won't need a block change
- l1:
- sub bx,cx ; ax has number of words after block change
- inc cx
- ror cx,1
- ror bx,1
-
- ;
- ; Draw the line
- ;
- even
- l4:
- cld
- rep stosw
-
- cmp bx,0
- je l5
-
- ;
- ; Handle block change and continue
- ;
- inc dx
- push dx
- call vgablock
- pop dx
-
- mov cx,bx
- xor bx,bx
- xor di,di
- jmp l4
-
- ;
- ; Finish up
- ;
- l5:
- Postfix
- vgahline endp
-
-
-
- ;
- ; Draw a line using bresenham's algorithm.
- ;
- ; Parameters:
- ; - x1
- ; - y1
- ; - x2
- ; - y2
- ; - Pixel value
- ;
- ; Locals:
- ; [bp-10] DX
- ; [bp-12] DY
- ; [bp-14] incr1
- ; [bp-16] incr2
- ;
- vgaline proc far
- Prefix
- sub sp,8
- ;
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
- ;
- ; Load window pointers
- ;
- mov ax,WinAddr
- mov es,ax ; Set ES to point to video memory
-
- push [bp+8]
- push [bp+6]
- call vgaoffset
- add sp,4
- mov di,ax
-
- ;
- ; Initialize for line draw
- ;
- mov ax,[bp+6] ; Get x1
- sub ax,[bp+10] ; Sub x2
- jg l1 ; Skip if positive
- neg ax
- l1: mov [bp-10],ax ; Save DX
-
- mov ax,[bp+8] ; Get y1
- sub ax,[bp+12] ; sub y2
- jg l2 ; Skip if positive
- neg ax
- l2: mov [bp-12],ax ; Save DY
-
- cmp ax,[bp-10] ; See if DY>DX
- jle xline ; Go do X oriented version
- jmp yline ; Go do Y oriented version
-
- ;
- ; X oriented version of draw line. Slope must be between -1 and 1 inclusive
- ;
- xline:
- mov cx, [bp-10] ; cx has increment control
-
- sal ax,1 ; DY*2
- mov [bp-14],ax ; Save incr1
- sub ax,[bp-10] ; 2*dy - dx
- mov bx,ax ; bx has D value
-
- mov ax,[bp-12] ; Get DY
- sub ax,[bp-10] ; (DY-DX)
- sal ax,1 ; 2*(DY-DX)
- mov [bp-16],ax ; Save incr2
-
- mov word ptr [bp-10],0 ; Assume going to left
- mov ax,[bp+6] ; Get x1
- sub ax,[bp+10] ; x1-x2
- jg l3
- mov word ptr [bp-10],1 ; Going to right
- l3:
- mov word ptr [bp-12],0 ; Assume going up
- mov ax,[bp+8] ; Get y1
- sub ax,[bp+12] ; y1-y2
- jg l5
- mov word ptr [bp-12],1 ; Going down
- l5:
-
- ;
- ; Main X oriented drawing loop.
- ; ax = pixel value
- ; bx = d
- ; cx = loop control
- ; dx = block number
- ; di = block offset
- ;
- mov ax,[bp+14]
- mov es:[di],al ; Write first pixel
- cmp cx,0 ; Check if done
- je xloopend
-
- xloop:
- cmp word ptr [bp-10],0 ; See if going left?
- je l7
- inc di ; going right
- jnc l8
- inc dx
- push dx
- call vgablock
- pop dx
- jmp l8
- l7:
- dec di ; going left
- jnc l8
- dec dx
- push dx
- call vgablock
- pop dx
- l8:
- cmp bx,0 ; test d<0
- jge l9
- add bx,[bp-14] ; d = d + incr1
- jmp l11
- l9:
- add bx,[bp-16] ; d = d + incr2
- cmp word ptr [bp-12],0 ; See if going up
- je l10
- add di,ScanWidth ; Go to next line
- jnc l11
- inc dx
- push dx
- call vgablock
- pop dx
- jmp l11
- l10:
- sub di,ScanWidth ; Go to previous line
- jnc l11
- dec dx
- push dx
- call vgablock
- pop dx
- l11:
- mov es:[di],al ; Write next pixel
- loop xloop
- xloopend:
- jmp done
-
-
- ;
- ; Y oriented version of draw line. Slope must be outside -1 and 1 inclusive
- ;
- yline:
- mov cx, [bp-12] ; cx has increment control
-
- mov ax, [bp-10]
- sal ax,1 ; DX*2
- mov [bp-14],ax ; Save incr1
- sub ax,[bp-12] ; 2*dx - dy
- mov bx,ax ; bx has D value
-
- mov ax,[bp-10] ; Get DX
- sub ax,[bp-12] ; (DX-DY)
- sal ax,1 ; 2*(DX-DY)
- mov [bp-16],ax ; Save incr2
-
- mov word ptr [bp-10],0 ; Assume going to left
- mov ax,[bp+6] ; Get x1
- sub ax,[bp+10] ; x1-x2
- jg l12
- mov word ptr [bp-10],1 ; Going to right
- l12:
- mov word ptr [bp-12],0 ; Assume going up
- mov ax,[bp+8] ; Get y1
- sub ax,[bp+12] ; y1-y2
- jg l13
- mov word ptr [bp-12],1 ; Going down
- l13:
-
- ;
- ; Main Y oriented drawing loop.
- ; ax = pixel value
- ; bx = d
- ; cx = loop control
- ; dx = block number
- ; di = block offset
- ;
- mov ax,[bp+14]
- mov es:[di],al ; Write first pixel
- cmp cx,0 ; Check if done
- je yloopend
-
- yloop:
- cmp word ptr [bp-12],0 ; See if going up?
- je l14
- add di,ScanWidth ; going down
- jnc l15
- inc dx
- push dx
- call vgablock
- pop dx
- jmp l15
- l14:
- sub di,ScanWidth ; going up
- jnc l15
- dec dx
- push dx
- call vgablock
- pop dx
- l15:
- cmp bx,0 ; test d<0
- jge l16
- add bx,[bp-14] ; d = d + incr1
- jmp l18
- l16:
- add bx,[bp-16] ; d = d + incr2
- cmp word ptr [bp-10],0 ; See if going left
- je l17
- inc di ; Go right
- jnc l18
- inc dx
- push dx
- call vgablock
- pop dx
- jmp l18
- l17:
- dec di ; Go left
- jnc l18
- dec dx
- push dx
- call vgablock
- pop dx
- l18:
- mov es:[di],al ; Write next pixel
- loop yloop
- yloopend:
-
- ;
- ; Clear stack and exit
- ;
- done:
- add sp,8
- Postfix
- vgaline endp
-
-
-
- ;
- ; Set colors from an array of rgb values.
- ;
- ; Parameters:
- ; - Array of colors
- ; - Start index
- ; - Number of colors
- ;
- vgasetcolor proc far
- Prefix
-
- les dx,[bp+6] ; Get address of colormap
- mov bx,[bp+10] ; Get first color index
- mov cx,[bp+12] ; Get Number of indexes
- mov ax,1012h ; Set block of color registers function
- int 10h
-
- Postfix
- vgasetcolor endp
-
-
-
- ;
- ; Fill a rectangular region with a given pixel value. Region is assumed to
- ; start on a even address and be an even width. Width and height values
- ; must be positive. Width and height values get modified.
- ;
- ; Parameters:
- ; - Row for upper left corner
- ; - Column for upper left corner
- ; - Width of rectangle
- ; - Height of rectangle
- ; - Pixel value
- ;
- ; Locals
- ; [bp-10] LineSkip
- ;
- vgafill proc far
- Prefix
- sub sp,2
- ;
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
-
- ;
- ; Load window pointers
- ;
- mov ax,WinAddr
- mov es,ax ; Set ES to point to video memory
-
- push [bp+8]
- push [bp+6]
- call vgaoffset
- add sp,4
-
- ;
- ; Setup control parameters for line draw.
- ;
- mov bx,ScanWidth
- sub bx,[bp+10]
- mov [bp-10], bx ; Amount to skip to get to next line
-
- mov di, ax ; Offset in di
- mov ax,[bp+14]
- mov ah,al ; ax has duplicated pixel value in al and ah
-
- even
- linestart:
- mov cx,BlockEnd ; Last point in counter
- sub cx,di ; cx has number of bytes till block change
-
- mov bx,[bp+10] ; bx has number of bytes in line
- dec bx
-
- cmp bx,cx
- ja l1
- mov cx,bx ; Won't need a block change
- l1:
- sub bx,cx ; ax has number of words after block change
- inc cx
- ror cx,1
- ror bx,1
-
- ;
- ; Draw the line
- ;
- even
- l4:
- cld
- rep stosw
-
- cmp di,0 ; Check for exact alignment
- je l5
- cmp bx,0
- je l6
-
- ;
- ; Handle block change and continue
- ;
- l5:
- inc dx
- push dx
- call vgablock
- pop dx
-
- cmp bx,0
- je l6
-
- mov cx,bx
- xor bx,bx
- xor di,di
- jmp l4
-
- ;
- ; Set up for next line
- ;
- l6:
- dec word ptr [bp+12]
- je l7
-
- add di,[bp-10] ; Go to start of next line
- jnc linestart
-
- inc dx ; Bump block pointer
- push dx
- call vgablock
- pop dx
- jmp linestart
-
- ;
- ; Finish up
- ;
- l7:
- add sp,2
- Postfix
- vgafill endp
-
-
- ;
- ; Copy a given rectangle into display memory at the specified address.
- ; All pixels from the source rectangle are copied with no masking.
- ; Coordinates are assumed to be correct and wraparound accounted for by
- ; the calling routine. The start address and rectangle width are assumed
- ; to be even values to permit faster copy. The passed values may be modified
- ; and should not be retained by the calling routine.
- ;
- ; Parameters:
- ; - Far pointer to source rectangle
- ; - Total width of source memory
- ; - Row for upper left corner
- ; - Column for upper left corner
- ; - Width of rectangle
- ; - Height of rectangle
- ;
- ; Locals
- ; [bp-10] LineSkip
- ;
- vgarect proc far
- Prefix
- sub sp,2
- ;
- mov ax,vgadata ; Load address of data segment
- mov ds,ax ; Set DS register
-
- ;
- ; Load window pointers
- ;
- mov ax,WinAddr
- mov es,ax ; Set ES to point to video memory
-
- push [bp+14]
- push [bp+12]
- call vgaoffset
- add sp,4
-
- ;
- ; Setup control parameters for line draw.
- ;
- mov di, ax ; Offset for output memory in di
-
- mov bx,ScanWidth
- sub bx,[bp+16]
- mov [bp-10], bx ; Amount to skip to get to next line on output
-
- mov bx,[bp+10]
- sub bx,[bp+16]
- mov [bp+10], bx ; Amount to go to next line on input data
-
- mov si, [bp+6] ; Offset for input memory
-
- even
- linestart:
- mov cx,BlockEnd ; Last point in counter
- sub cx,di ; cx has number of bytes till block change
-
- mov bx,[bp+16] ; bx has number of bytes in line
- dec bx
-
- cmp bx,cx
- ja l1
- mov cx,bx ; Won't need a block change
- l1:
- sub bx,cx ; bx has number of words after block change
- inc cx
- ror cx,1
- ror bx,1
-
-
- ;
- ; Draw the line
- ;
- even
- l4:
- push ds ; Save segment for vgadata
- mov ax, [bp+8]
- mov ds,ax ; Set segment for source rectangle
-
- cld
- rep movsw
-
- pop ds ; Get segment for vgadata
- cmp di,0 ; Check for exact alignment
- je l5
- cmp bx,0
- je l6
-
- ;
- ; Handle block change and continue
- ;
- l5:
- inc dx
- push dx
- call vgablock
- pop dx
-
- cmp bx,0
- je l6
-
- mov cx,bx
- xor bx,bx
- xor di,di
- jmp l4
-
- ;
- ; Set up for next line
- ;
- l6:
- dec word ptr [bp+18]
- je l7
-
- add si,[bp+10] ; Goto next line in input
- add di,[bp-10] ; Go to start of next line on output
- jnc linestart
-
- inc dx ; Bump block pointer
- push dx
- call vgablock
- pop dx
- jmp linestart
-
- ;
- ; Finish up
- ;
- l7:
- add sp,2
- Postfix
- vgarect endp
-
-
- vgacode ends
- end
-